#pragma once

#include "localsem.hpp"

typedef int MyDataType;

template <typename T>
struct MyData
{
    const char *_name;
    Local_Sem::LocalSem *_myprodsem;
    Local_Sem::LocalSem *_myconssem;
    MyData(const char *name, Local_Sem::LocalSem *myprodsem, Local_Sem::LocalSem *myconssem)
        : _name(name), _myprodsem(myprodsem), _myconssem(myconssem)
    {
    }
};

void *producer(void *argv)
{
    MyData<MyDataType> *myproducer = static_cast<MyData<MyDataType> *>(argv);
    while (1)
    {
        myproducer->_myprodsem->P();
        std::cout << myproducer->_name << " send: " << std::endl;
        myproducer->_myconssem->V();
        sleep(1);
    }
}

void *consumer(void *argv)
{
    MyData<MyDataType> *myconsumer = static_cast<MyData<MyDataType> *>(argv);
    while (1)
    {
        myconsumer->_myconssem->P();
        std::cout << myconsumer->_name << " receive: " << std::endl;
        myconsumer->_myprodsem->V();
        sleep(3);
    }
}

void linux_prodcons_enc()
{
    Local_Sem::LocalSem *mypprodsem = new Local_Sem::LocalSem(1);
    Local_Sem::LocalSem *mypconssem = new Local_Sem::LocalSem(1);

    MyData<MyDataType> *myproducer = new MyData<MyDataType>("producer", mypprodsem, mypconssem);
    MyData<MyDataType> *myconsumer = new MyData<MyDataType>("consumer", mypprodsem, mypconssem);

    pthread_t pth1_id;
    pthread_create(&pth1_id, NULL, producer, (void *)(myproducer));
    pthread_t pth2_id;
    pthread_create(&pth2_id, NULL, consumer, (void *)(myconsumer));

    pthread_join(pth1_id, nullptr);
    pthread_join(pth2_id, nullptr);

    delete mypprodsem;
    delete mypconssem;
}
